﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Compiler.TableOfSymbols;

namespace Compiler.CompilerAPI.Contexts
{
    /// <summary>
    /// Стек вложенных контекстов
    /// </summary>
    public class StackContext : Context
    {
        /// <summary>
        /// Список контекстов. Самый вложенный контекст -- последний
        /// </summary>
        private LinkedList<Context> contexts;

        /// <summary>
        /// Возвращает самый вложенный контекст
        /// </summary>
        public Context CurrentContext
        { 
            get 
            {
                if (contexts.Count == 0)
                    throw new InvalidOperationException("Context stack is empty");
                else
                    return contexts.Last.Value;
            } 
        }

        public StackContext(NETTypesBijectiveMap typesBijectiveMap)
            : base(typesBijectiveMap)
        {
            contexts = new LinkedList<Context>();
        }

        public StackContext(NETTypesBijectiveMap typesBijectiveMap, Context outerContext)
            : this(typesBijectiveMap)
        {
            if (outerContext == null)
                throw new ArgumentNullException("outerContext can not be null");
            contexts.AddFirst(outerContext);
        }

        public void Push(Context innerContext)
        {
            if (innerContext == null)
                throw new ArgumentNullException("innerContext can not be null");
            contexts.AddLast(innerContext);
        }

        public Context Pop()
        {
            if (contexts.Count == 0)
                throw new InvalidOperationException("Context stack is empty, nothing to pop");
            Context result = contexts.Last.Value;
            contexts.RemoveLast();
            return result;
        }

        /// <summary>
        /// Ищет в контексте информацию о типе
        /// </summary>
        /// <param name="name">Имя типа</param>
        /// <param name="qualifier">Квалификатор пространств имён</param>
        /// <returns>Информацию о результатах поиска (включает тип, если найден)</returns>
        public override TypeSearchInfo TryGetTypeInfo(string name, string qualifier)
        {
            TypeSearchInfo result = new TypeSearchInfo(true, false);
            var last = contexts.Last;
            while (last != null)
            {
                Context currConcept = last.Value;
                result = currConcept.TryGetTypeInfo(name, qualifier);
                if (result.TypeInfo != null || result.AmbiguityType)
                    return result;
                last = last.Previous;
            }
            return result;
        }

        /// <summary>
        /// Проверяет, определена ли в контексте какая-нибудь 
        /// структурная единица с именем name
        /// </summary>
        /// <param name="name">Имя</param>
        /// <returns>Всегда ложь, так как в контексте-стеке ничего не определяется непосредственно</returns>
        public override bool ContainsDefinedName(string name)
        {
            return false;
        }

        /// <summary>
        /// Добавляет в самый вложенный контекст определение новой структурной единицы
        /// </summary>
        /// <param name="name">Имя новой единицы</param>
        /// <param name="data">Данные структурной единицы</param>
        public override void AddNewDefinition(string name, SymbolTableData data)
        {
            this.CurrentContext.AddNewDefinition(name, data);
        }
    }
}
